package cn.bugstack.ai.domain.agent.service.dispatch;

import cn.bugstack.ai.domain.agent.adapter.repository.IAgentRepository;
import cn.bugstack.ai.domain.agent.model.entity.ExecuteCommandEntity;
import cn.bugstack.ai.domain.agent.model.valobj.AiAgentVO;
import cn.bugstack.ai.domain.agent.service.IAgentDispatchService;
import cn.bugstack.ai.domain.agent.service.IExecuteStrategy;
import cn.bugstack.ai.types.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;

import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * Agent 调度服务实现
 * 
 * 【执行流程第二层：策略调度器】
 * 职责：
 * 1. 根据 Agent ID 查询数据库配置
 * 2. 获取执行策略类型（autoAgentExecuteStrategy / fixedAgentExecuteStrategy /
 * flowAgentExecuteStrategy）
 * 3. 从策略Map中选择对应的执行策略
 * 4. 提交到线程池异步执行
 * 
 * 流程位置：
 * AiAgentController → AgentDispatchService → 执行策略（Auto/Fixed/Flow）
 * 
 * 设计模式：策略模式 + 依赖注入
 *
 * @author xiaofuge bugstack.cn @小傅哥
 *         2025/9/6 06:55
 */
@Slf4j
@Service
public class AgentDispatchDispatchService implements IAgentDispatchService {

    /**
     * 执行策略映射表
     * Spring 自动注入所有实现了 IExecuteStrategy 接口的 Bean
     * 
     * Map 结构：
     * {
     * "autoAgentExecuteStrategy" -> AutoAgentExecuteStrategy 实例,
     * "fixedAgentExecuteStrategy" -> FixedAgentExecuteStrategy 实例,
     * "flowAgentExecuteStrategy" -> FlowAgentExecuteStrategy 实例
     * }
     */
    @Resource
    private Map<String, IExecuteStrategy> executeStrategyMap;

    /** 数据仓储 - 用于查询 Agent 配置信息 */
    @Resource
    private IAgentRepository repository;

    /** 线程池 - 用于异步执行 Agent 任务，避免阻塞 HTTP 请求线程 */
    @Resource
    private ThreadPoolExecutor threadPoolExecutor;

    /**
     * 调度方法 - 执行 Agent 任务的核心入口
     * 
     * 执行流程：
     * 1. 查询数据库获取 Agent 配置（包含策略类型）
     * 2. 根据策略类型从 Map 中获取对应的执行策略实例
     * 3. 提交到线程池异步执行
     * 4. 异步线程中执行策略，通过 emitter 实时推送结果
     * 5. 最后调用 emitter.complete() 完成流式输出
     * 
     * @param requestParameter 执行命令实体（包含 aiAgentId、message、sessionId、maxStep）
     * @param emitter          SSE 流式响应对象，用于实时推送执行进度
     * @throws Exception 如果策略不存在或执行失败
     */
    @Override
    public void dispatch(ExecuteCommandEntity requestParameter, ResponseBodyEmitter emitter) throws Exception {
        // ========== 第一步：查询 Agent 配置 ==========
        // 从数据库 ai_agent 表查询 Agent 的配置信息
        // 包含：agentId, agentName, strategy(策略类型), status 等
        AiAgentVO aiAgentVO = repository.queryAiAgentByAgentId(requestParameter.getAiAgentId());

        // ========== 第二步：获取策略类型 ==========
        // 从 Agent 配置中获取策略类型字段
        // 例如："autoAgentExecuteStrategy"、"fixedAgentExecuteStrategy"、"flowAgentExecuteStrategy"
        String strategy = aiAgentVO.getStrategy();

        // ========== 第三步：从策略映射表获取执行策略实例 ==========
        // 根据策略名称从 executeStrategyMap 中获取对应的策略 Bean
        // 这是策略模式的核心：通过配置动态选择执行策略
        IExecuteStrategy executeStrategy = executeStrategyMap.get(strategy);

        // 如果策略不存在，抛出业务异常
        if (null == executeStrategy) {
            throw new BizException("不存在的执行策略类型 strategy:" + strategy);
        }

        // ========== 第四步：异步执行策略 ==========
        // 为什么要异步？
        // 1. Agent 执行可能需要很长时间（调用 LLM、等待响应）
        // 2. 避免阻塞 HTTP 请求线程
        // 3. 通过 SSE 实时推送结果，不需要等待全部完成
        threadPoolExecutor.execute(() -> {
            try {
                // 执行策略的 execute 方法
                // 策略会按照自己的逻辑执行（如 Auto Agent 会执行 Step1~4）
                // 执行过程中通过 emitter 发送 SSE 消息给前端
                executeStrategy.execute(requestParameter, emitter);

            } catch (Exception e) {
                // 如果执行过程中出现异常，记录日志
                log.error("AutoAgent执行异常：{}", e.getMessage(), e);
                try {
                    // 尝试通过 SSE 发送错误信息给前端
                    emitter.send("执行异常：" + e.getMessage());
                } catch (Exception ex) {
                    log.error("发送异常信息失败：{}", ex.getMessage(), ex);
                }

            } finally {
                try {
                    // 无论成功还是失败，最后都要调用 complete() 完成流式输出
                    // 这会告诉前端："我已经发送完所有消息了"
                    emitter.complete();
                } catch (Exception e) {
                    log.error("完成流式输出失败：{}", e.getMessage(), e);
                }
            }
        });

    }

}
